-- Variables
local updateInterval = .5
local timeToUpdate = 0
local numChildren = -1
local pairs = pairs
local select = select
local TidyPlates_Message = ""

	-- EXPERIMENT: 
	local isTimeToUpdate = false
	local updateTime = 0
	local updateInterval = .3
	-- ]] EXPERIMENT: 
	
	
local PlateHandler = CreateFrame("Frame")

local styleBasic = {}
local styleMulti = {}
local useMultiStyle = false

-- LoadStyle; Returns a new table, using 'template' as a base, and updating with 'custom'
function LoadStyle(template, custom)
	local newconfig = {}
	local propertylist = {}
	local category, property, defaultvalue, customvalue
	if type(custom) == "table" then
		for category, propertylist in pairs(template) do 
		  newconfig[category] = {}
		  for property, defaultvalue in pairs(propertylist) do
			if type(custom[category]) == "table" then customvalue = custom[category][property] else customvalue = nil end
			if type(customvalue) == type(defaultvalue) then newconfig[category][property] = customvalue else newconfig[category][property] = defaultvalue end
		  end
		end
		return newconfig
	else return nil
	end
end

-- LoadMultiStyle; Returns a table of style tables
function LoadMultiStyle(template, styleList)
	local style, styleData = {}
	local count = 0
	local checkedStyleList = {}
	local tempStyle = {}
	if type(styleList) == "table" then
		for style, styleData in pairs(styleList) do 
			tempStyle = LoadStyle(template, styleData)
			if tempStyle then 
				count = count + 1
				checkedStyleList[count] = tempStyle
			end
		end
		checkedStyleList.count = count
		if count > 0 and NAMEPLATE_MULTISTYLE_DELEGATE then useMultiStyle = true end
		return checkedStyleList
	else 
		checkedStyleList.count = 0
		return nil
	end
end

local function shouldDisplayThreat(unit)
	if InCombatLockdown() and unit.reaction ~= "FRIENDLY" and IsThreatWarningEnabled() then return true 
	else return false end
end

local function ThreatFromColor( object , name)
	local redCan, greenCan, blueCan, alphaCan = object:GetVertexColor()
	local shown
	if not object:IsShown() then return "LOW" end
	if greenCan > .7 then return "MEDIUM" end
	if redCan > .7 then return "HIGH" end
end

local function ReactionFromHealthbarColor(object)
		local redCan, greenCan, blueCan, alphaCan = object:GetStatusBarColor()
		if redCan < .01 and blueCan < .01 and greenCan > .99 then return "FRIENDLY" 
		elseif redCan < .01 and blueCan > .99 and greenCan < .01 then return "FRIENDLY" 
		elseif redCan > .99 and blueCan < .01 and greenCan > .99 then return "NEUTRAL" 
		else return "HOSTILE" end
end

local function SetFrameBySize(frame, width, height, anchor, offX, offY)
	frame:ClearAllPoints()
	frame:SetWidth(width)
	frame:SetHeight(height)
	frame:SetPoint(anchor, offX, offY)
end
			
local function SetFrameByStyle(frame, style, anchorTo)
	frame:ClearAllPoints()
	frame:SetWidth(style.width)
	frame:SetHeight(style.height)
	frame:SetPoint(style.anchor, anchorTo, style.anchor, style.x, style.y)
end

local function ApplyBarSettings(statBar, statbarStyle, baseFrame)
	statBar:SetStatusBarTexture(statbarStyle.texture)
	SetFrameByStyle(statBar, statbarStyle, baseFrame)
	statBar:SetAlpha(.7)
	statBar:SetOrientation(statbarStyle.orientation)
end

function ApplyFontStyle(text, style) 
	text:SetFont(style.typeface, style.size)
	text:SetJustifyH(style.align)
	text:SetJustifyV(style.vertical)
	text:SetDrawLayer("ARTWORK")
	if style.shadow then 
		text:SetShadowOffset(1,-1)
		text:SetShadowColor(0,0,0,1)
	else
		text:SetShadowColor(0,0,0,0)
	end
end

function ApplyTexture(region,texture) 
	region:SetTexture(texture) 
	region:SetTexCoord(0,1,0,1) 
end

local function ApplyPlateTheme(statBar)
	------------ Source Elements  ------------
	local _, index
	local plate = statBar:GetParent()
	local healthBar, castBar = plate:GetChildren()
	local threatGlow, healthBorder, castBorder, spellIcon, highlightTexture, nameText, levelText, dangerSkull, raidIcon, eliteIcon = plate:GetRegions()
	if( not nameText.SetFont ) then return end
	local baseFrame = plate.baseFrame
	local plateStyle = plate.plateStyle
	local unit = plate.unit
	local color = plate.color
		------------ Derived Properties  ------------
	unit.threatSituation = ThreatFromColor(threatGlow, nameText:GetText())
	unit.reaction = ReactionFromHealthbarColor(healthBar)
	unit.isDangerous = dangerSkull:IsShown()
	unit.isElite = eliteIcon:IsShown()
	unit.name = nameText:GetText()
	unit.isTarget = (plate:GetAlpha() == 1) and (UnitName("target") == unit.name)
	unit.level = levelText:GetText()
	unit.health = healthBar:GetValue()
	_, unit.healthmax = healthBar:GetMinMaxValues()
	------------ Get Current Plate Style ------------
	if useMultiStyle then 
		index = NAMEPLATE_MULTISTYLE_DELEGATE(unit)
		plateStyle = styleMulti[index]
	else plateStyle = styleBasic end
	------------ Configure Plate Elements ------------
	-- Configure the unitframe box
	if not InCombatLockdown() then
		plate:SetWidth(plateStyle.frame.width)
		plate:SetHeight(plateStyle.frame.height)
	end
	-- Configure the Alignment frame
	SetFrameByStyle(baseFrame, plateStyle.frame, plate)
	-- Configure the Health Border Overlay
	ApplyTexture(healthBorder, plateStyle.textures.standardtexture)
	SetFrameByStyle(healthBorder, plateStyle.textures, plate)
	-- Configure Highlight Texture
	ApplyTexture(highlightTexture, plateStyle.textures.glowtexture)
	highlightTexture:SetAllPoints(healthBorder)
	-- Configure Threat Glow Overlay
	ApplyTexture(plate.threatOverlay, plateStyle.textures.emptyTexture)
	plate.threatOverlay:SetAllPoints(healthBorder)
	plate.threatOverlay:Hide()
	-- Configure the Cast Bar Border
	ApplyTexture(castBorder, plateStyle.textures.casttexture)
	SetFrameByStyle(castBorder, plateStyle.textures, plate)
	-- Configure the Name Text
	if plateStyle.options.showName then
		nameText:Show()
		ApplyFontStyle(nameText, plateStyle.name)
		SetFrameByStyle(nameText, plateStyle.name, baseFrame)
	else nameText:Hide() end
	-- Configure the Level Text
	if plateStyle.options.showLevel then
		levelText:Show()
		ApplyFontStyle(levelText, plateStyle.level)
		SetFrameByStyle(levelText, plateStyle.level, baseFrame)
	else levelText:Hide() end
	-- Configure Special Text
	if plateStyle.options.showSpecialText then
		plate.specialText:Show()
		ApplyFontStyle(plate.specialText, plateStyle.specialText)
		SetFrameByStyle(plate.specialText, plateStyle.specialText, baseFrame)
	else plate.specialText:Hide() end
	-- Raid Icon/Lucky Charms..
	raidIcon:SetDrawLayer("OVERLAY")
	SetFrameByStyle(raidIcon, plateStyle.raidicon, baseFrame)
	-- Spellcast Icon
	spellIcon:SetDrawLayer("OVERLAY")
	SetFrameByStyle(spellIcon, plateStyle.spellicon, baseFrame)
	-- Skull Icon
	if plateStyle.options.showDangerSkull then
		dangerSkull:SetDrawLayer("OVERLAY")
		SetFrameByStyle(dangerSkull, plateStyle.dangerskull, baseFrame)
	else dangerSkull:SetAlpha(0) end
	-- Hide redundant items
	threatGlow:SetTexture(plateStyle.textures.emptyTexture )
	eliteIcon:SetAlpha(0)
	
	------------ Configure the Status Bars (Health and Cast)  ------------
	ApplyBarSettings(healthBar, plateStyle.healthbar, baseFrame)
	ApplyBarSettings(castBar, plateStyle.castbar, baseFrame)
	
	------------ Manage Active Elements  ------------
	if unit.isElite then 
		plate.threatOverlay:SetTexture(plateStyle.textures.eliteThreatTexture)
		ApplyTexture(healthBorder, plateStyle.textures.eliteTexture)
	else 
		plate.threatOverlay:SetTexture(plateStyle.textures.nonEliteThreatTexture) 
	end
	
	if shouldDisplayThreat(unit) then
		color = plateStyle.threatcolor[unit.threatSituation]
		plate.threatOverlay:Show()
		plate.threatOverlay:SetVertexColor(color.r, color.g, color.b, color.a)
	end
	
	if plateStyle.options.showSpecialText and NAMEPLATE_SPECIALTEXT_DELEGATE then
		plate.specialText:SetText(NAMEPLATE_SPECIALTEXT_DELEGATE(unit))
	end
end

local function ApplyPlateHooks(plate)
	local health, cast
	health, cast = plate:GetChildren()
	local _, _, _, _, _, nameText, _, _, _, _ = plate:GetRegions()
	-- Hook for Health bar
	health:HookScript("OnValueChanged", ApplyPlateTheme) 
	health:HookScript("OnShow", ApplyPlateTheme) 
	
	-- EXPERIMENT: 
	--if useMultiStyle then health:HookScript("OnUpdate", function (self ) if isTimeToUpdate then ApplyPlateTheme(self) end end) end
	-- ]] EXPERIMENT: 
	
	-- Hook events for updates
	health:RegisterEvent("PLAYER_REGEN_DISABLED")
	health:RegisterEvent("PLAYER_REGEN_ENABLED")
	health:RegisterEvent("PLAYER_TARGET_CHANGED")
	health:RegisterEvent("UNIT_THREAT_LIST_UPDATE")
	health:RegisterEvent("UNIT_THREAT_SITUATION_UPDATE")
	health:RegisterEvent("UNIT_COMBAT")
	health:RegisterEvent("UNIT_ATTACK")
	health:HookScript("OnEvent", ApplyPlateTheme )
	-- Hook for Cast bar
	cast:HookScript("OnValueChanged", ApplyPlateTheme) 
	cast:HookScript("OnShow", ApplyPlateTheme) 
	-- Additional Elements
	plate.baseFrame = CreateFrame("Frame", nil, plate)
	plate.threatOverlay = plate:CreateTexture(nil, "ARTWORK")
	plate.specialText = plate:CreateFontString(nil, "ARTWORK")
	plate.plateStyle = {}
	plate.unit = {}
	plate.color = {}
	-- Update right away
	ApplyPlateTheme(health)
end

local function IsFrameNameplate(frame)
	local region = frame:GetRegions()
	return region and region:GetObjectType() == "Texture" and region:GetTexture() == "Interface\\TargetingFrame\\UI-TargetingFrame-Flash" 
end


	
local function captureNameplates(...)
	for i=1, select("#", ...) do 
		local plate = select(i, ...)
		if IsFrameNameplate(plate) then
			if not plate.baseFrame then
				ApplyPlateHooks(plate)
			end
		end
	end
end

function setUpdateTime()
		if (GetTime() > updateTime) then
			isTimeToUpdate = true
			updateTime = GetTime() + updateInterval 
		else isTimeToUpdate = false end
end
	
PlateHandler:SetScript("OnUpdate", function(self) 
		local curChildren = WorldFrame:GetNumChildren()
		if (curChildren ~= numChildren) then
			numChildren = curChildren
			captureNameplates(WorldFrame:GetChildren()) 
		end	
		-- Experiment:
		--if useMultiStyle then setUpdateTime() end
		-- Experiment:
end)

PlateHandler:RegisterEvent("VARIABLES_LOADED")
PlateHandler:SetScript("OnEvent", function(self)
	if event == "VARIABLES_LOADED" then
		if MY_NAMEPLATE_STYLE_BASIC then 
			TidyPlates_Message = "Loaded Single-Plate Theme"
			styleBasic = LoadStyle(DEFAULT_NAMEPLATE_SKIN, MY_NAMEPLATE_STYLE_BASIC)
		elseif MY_NAMEPLATE_STYLE_MULTI then
			TidyPlates_Message = "Loaded Multi-Plate Theme"
			styleMulti = LoadMultiStyle(DEFAULT_NAMEPLATE_SKIN, MY_NAMEPLATE_STYLE_MULTI)
			styleBasic = DEFAULT_NAMEPLATE_SKIN
		else 
			TidyPlates_Message = "Loaded Default Theme"
			styleBasic = DEFAULT_NAMEPLATE_SKIN 
		end
	end
end)

function slash_TidyPlates(arg) ChatFrame1:AddMessage('TidyPlates: '..TidyPlates_Message); end
SLASH_TIDYPLATES1 = '/tidyplates'
SlashCmdList['TIDYPLATES'] = slash_TidyPlates;

--[[
Notes:
	- The invisible nameplate frame ( the 'plate' variable, in this program),
	which captures the mouse-clicks and mouse-overs, is obviously a secure frame.
	This means that it cannot be resized while in combat.  A side-effect (to us)
	is that the selection box cannot be modified in combat.  Designers should
	acknowledge this limitation, since it can present a usage problem for odd
	shapes.
	- The level text updates itself periodically, without warning
	- 
	
	- Things to add:
		* Show/Hide Handler (Multi-platestyle handler would solve this)
		* CurrentTarget Frame-link
		* SpecialImage frame
		* Multi Plate-style, and handler
	
--]]







